package org.litepal.crud;

import java.lang.reflect.InvocationTargetException;

import org.litepal.LitePalBase;
import org.litepal.crud.model.AssociationInfo;
import org.litepal.util.Const;

/**
 * Deals with one2one condition when comes to two models are associated.
 * 
 * @author Tony Green
 * @since 1.1
 */
public class One2OneAnalyzer extends AssociationsAnalyzer {

	/**
	 * Analyzing the RelatedInfo. It will help baseObj assign the necessary
	 * values automatically. If the two associated models has both way
	 * association but developer has only build one way association in model, it
	 * will force to build the both way association. Besides the
	 * {@link DataSupport#associatedModels} will be found and put here.
	 * 
	 * @param baseObj
	 *            The baseObj currently want to persist.
	 * @param associatedInfo
	 *            The associated info analyzed by
	 *            {@link LitePalBase#getRelatedInfo}.
	 * @throws SecurityException
	 * @throws IllegalArgumentException
	 * @throws NoSuchMethodException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	void analyze(DataSupport baseObj, AssociationInfo associationInfo) throws SecurityException,
			IllegalArgumentException, NoSuchMethodException, IllegalAccessException,
			InvocationTargetException {
		if (getBaseClassName(baseObj).equals(associationInfo.getClassHoldsForeignKey())) {
			// on the side with foreign key
			DataSupport associatedModel = (DataSupport) takeGetMethodValueByField(baseObj,
					associationInfo.getAssociateOtherModelFromSelf());
			if (associatedModel != null) {
				putSetMethodValueByField(associatedModel,
						associationInfo.getAssociateSelfFromOtherModel(), baseObj);
				baseObj.addNewAssociatedModel(associatedModel, Const.Model.ONE_TO_ONE, true);
				associatedModel.addNewAssociatedModel(baseObj, Const.Model.ONE_TO_ONE, false);
			}
		} else {
			// on the side without foreign key
			DataSupport associatedModel = (DataSupport) takeGetMethodValueByField(baseObj,
					associationInfo.getAssociateOtherModelFromSelf());
			if (associatedModel != null) {
				putSetMethodValueByField(associatedModel,
						associationInfo.getAssociateSelfFromOtherModel(), baseObj);
				baseObj.addNewAssociatedModel(associatedModel, Const.Model.ONE_TO_ONE, false);
				associatedModel.addNewAssociatedModel(baseObj, Const.Model.ONE_TO_ONE, true);
			}
		}
	}
}
